﻿/********************************************************************************/
/* 	enemy.d																		*/
/*------------------------------------------------------------------------------*/
/*	製作		（　゜ワ゜）ノ　／　松久貫太									*/
/*	製作開始　	2007/05/11														*/
/*	MAIL		omega@personal.email.ne.jp										*/
/*	URL		http://nagoya.cool.ne.jp/o_mega										*/
/*																				*/
/*	このソースは「やわらかライセンス」の元で配布されています。					*/
/*-更新履歴---------------------------------------------------------------------*/
/*	2007/08/04 製作開始															*/
/*-その他-----------------------------------------------------------------------*/
/*	なし																		*/
/********************************************************************************/

private import hell2;
private import actor;
private import vector;
private import screen;
private import player;
private import effect;
private import shot;
private import eshot;
private import state;

private import std.math;
private import std.math2;

private import defines;


class EnemySpec
{
	double size;
	
	enum TYPE{
		TANK,
		BULLET
	}
	TYPE type;
	
	this(TYPE t){
		type = t;
		if(t == TYPE.TANK) size = 1.0;
		if(t == TYPE.BULLET) size = 0.4;
	}
}

class EnemyActor : ActorPool!(Enemy)
{
public:
	GameMain gamemain;
	
	this(GameMain gm,int n)
	{
		gamemain = gm;
		super(n);
	}
	
	void add(Vec3 p ,Vec3 v,EnemySpec esp)
	{
		Enemy s = this.getInstance();
		if(s)
		{
			s.init(gamemain,p,v,esp);
		}
	}
	
	Enemy getNearestEnemy(Vec3 v)
	{
		float dist = 99999999.0;
		Enemy result = null;
		
		foreach(Enemy s;actors)
		{
			if(s.exist)
			{
				float d = s.position.getDistSqrt(v);
				if(d < dist)
				{
					dist = d;
					result = s;
				}
			}
		}
		return result;
	}
	void drawHigh()
	{
		foreach(Enemy a;actors)
		{
			if(a.exist)
			{
				a.drawHigh();
			}
		}
	}
	
	int countEnemy(EnemySpec.TYPE type){
		int res = 0;
		foreach(Enemy a;actors)
		{
			if(a.exist)
			{
				if(a.spec.type == type) res++;
			}
		}
		
		return res;
	}
	void destroyAll(){
		foreach(Enemy a;actors){
			if(a.exist) a.destroy();
		}
	}
}


/* */
class Enemy : Actor
{
public:
	enum TARLET{
		FREE,
		TARGET,
		FIRE,
		RELOAD
	};
	
	Vec3 speed;
	Vec3 rotation;
	int timer;
	int damage_timer;
	
	GameMain gamemain;
	float tarlet;
	int life;
	TARLET tarlet_mode;
	int tarlet_timer;
	float tarlet_nockback;
	
	EnemySpec spec;
	
	static const float TARLET_SPEED = 0.008;
	static const float RELOAD_TIME = 300;
	static const float TARGET_TIME = 10;
	
	static const float TARLET_NOCKFORCE = 1.0;
	
	static const float MOVE_SPEED = 0.02;
	static const float MAX_RANGE = CHAR_X_ABSMAX / 2;
	static const float SHOT_RANGE = CHAR_X_ABSMAX / 2;
	
	static const int DAMAGE_WAIT = 60;
	
	this()
	{
		super();
	}
	
	void init(GameMain gm,Vec3 p,Vec3 v,EnemySpec ep)
	{
		gamemain = gm;
		exist = true;
		position = new Vec3(p);
		speed = new Vec3(v);
		rotation = new Vec3( 0 , 0, speed.atan2D());
		tarlet = speed.atan2D() + Hell_randInt(-60,60) * 3.141592 / 180;//v.atan2D(v);
		spec = ep;
		timer = 0;
		damage_timer = 0;
		
		if(spec.type == EnemySpec.TYPE.TANK){
			life = 1;
			if(Hell_randInt(0,100) < 5) life = 50;
			
			tarlet_mode = TARLET.FREE;
			tarlet_timer = 0;
			tarlet_nockback = 0;
		}else{
			life = 1;
		}
		
		position.z = CHAR_Z_SURFACE;
	}
	
	void move()
	{
		if(!exist) return;
		
		if(damage_timer > 0){
			damage_timer--;
		}else{
			moveNormal();
		}
		collision();
	}
	
	void moveNormal(){
		timer++;
		
		if(spec.type == EnemySpec.TYPE.TANK){
			position += speed;
			//speed.toVector2D(MOVE_SPEED , rotation.z);
			if(position.x > CHAR_X_ABSMAX - 1)
			{
				position += speed * 3;
			}
			if(position.x < -CHAR_X_ABSMAX + 1)
			{
				position += speed * 3;
			}
			if(position.y > CHAR_Y_ABSMAX - 1)
			{
				position += speed * 3;
			}
			if(position.y < -CHAR_Y_ABSMAX + 1)
			{
				position += speed * 3 ;
			}
			
			if((fabs(position.x) > CHAR_X_ABSMAX + 3 || fabs(position.y) > CHAR_Y_ABSMAX + 3)&& timer > 600){
				exist = false;
				return;
			}
			// ターレット
			tarlet_nockback *= 0.5;
			
			Player p = gamemain.playeractor.getNearest(position);
			if(!p || position.getDist(p.position) > MAX_RANGE){
				tarlet_mode = TARLET.FREE;
			}else if(tarlet_mode == TARLET.FREE){
				tarlet_mode = TARLET.TARGET;
			}
			
			if(tarlet_mode != TARLET.FREE){
				double tarlet_tg = position.atan2D(p.position);
				double dist = tarlet_tg - tarlet;
				while(dist > 3.141592 * 2) dist -= 3.141592 * 2;
				while(dist < 0) dist += 3.141592 * 2;
				
				if(tarlet_mode == TARLET.TARGET){
					if(fabs(dist) < TARLET_SPEED){
						tarlet = tarlet_tg;
						tarlet_mode = TARLET.FIRE;
						tarlet_timer = 0;
					}else{
						if(dist > 3.141592){
							tarlet -= TARLET_SPEED;
						}else{
							tarlet += TARLET_SPEED;
						}
					}
				}else if(tarlet_mode == TARLET.FIRE){
					if(tarlet_timer++ > TARGET_TIME){
						// 撃て
						tarlet_timer = 0;
						tarlet_mode = TARLET.RELOAD;
						tarlet_nockback = TARLET_NOCKFORCE;
						
						gamemain.enemyactor.add(
							new Vec3(position) + new Vec3(1 , tarlet),
							new Vec3(0.3 , tarlet ) ,
							new EnemySpec(EnemySpec.TYPE.BULLET));
					}
				}else if(tarlet_mode == TARLET.RELOAD){
					if(tarlet_timer++ > RELOAD_TIME){
						tarlet_mode = TARLET.FREE;
						tarlet_timer = 0;
					}
				}
			}else if(tarlet_mode == TARLET.FREE){
				tarlet += sin(timer / 60.0) * TARLET_SPEED;
			}
		}else{
			// 敵弾
			if(timer > 15) position += speed;
			if((timer - 15) > SHOT_RANGE / speed.getDist()) exist = false;
			if(fabs(position.x) > CHAR_X_ABSMAX + 3 || fabs(position.y) > CHAR_Y_ABSMAX + 3){
				exist = false;
				return;
			}
		}
	}
	
	void collision(){
		// collision
		if(spec.type != EnemySpec.TYPE.TANK) return;
		
		Shot s = gamemain.shotactor.getNearestShot(position);
		if(s)
		{
			if(s.position.getDist(position) < getSize() + s.getSize())
			{
				// Damage
				life--;
				damage_timer = DAMAGE_WAIT;
				/*
				position += s.speed * 0.5; // ノックバック
				speed += s.speed * 0.002;
				rotation.x += Hell_randInt(-20,20) / 1.0;
				rotation.y += Hell_randInt(-20,20) / 1.0;
				rotation.z += Hell_randInt(-20,20) / 1.0;
				*/
				s.destory();
				
				if(life < 1){
					destroy();
				}
			}
		}
	}
	
	void destroy(){
		if(spec.type == EnemySpec.TYPE.TANK){
			Hell_playWAV("destroy");
			exist = false;
			
			for(int t=0;t<24;t++)
			{
				Vec3 p = new Vec3(position);
				p.x += Hell_randInt(-10,10) / 5.0;
				p.y += Hell_randInt(-10,10) / 5.0;
				gamemain.addEffect(p , new Vec3() ,
					EFFECTTYPE.TRIANGLE);
			}
			for(int t=0;t<128;t++)
			{
				Vec3 p = new Vec3(position);
				p.x += Hell_randInt(-10,10) / 5.0;
				p.y += Hell_randInt(-10,10) / 5.0;
				double r = Hell_randInt(0,360) / 180.0 * 3.141592;
				double rr = Hell_randInt(0,360) / 180.0 * 3.141592;
				gamemain.addEffect(p , new Vec3(0.5 * cos(r) * cos(rr) , 0.5 * sin(r) * cos(rr) , 0.5 * sin(rr)) ,
					EFFECTTYPE.POINT);
			}
			
			gamemain.score += 10;
		}else{
			exist = false;
			/*
			for(int t=0;t<32;t++)
			{
				Vec3 p = new Vec3(position);
				p.x += Hell_randInt(-10,10) / 5.0;
				p.y += Hell_randInt(-10,10) / 5.0;
				double r = Hell_randInt(0,360) / 180.0 * 3.141592;
				double rr = Hell_randInt(0,360) / 180.0 * 3.141592;
				gamemain.addEffect(p , new Vec3(1.0 * cos(r) * cos(rr) , 0.5 * sin(r) * cos(rr) , 0.5 * sin(rr)) ,
					EFFECTTYPE.POINT);
			}
			*/
		}
	}
	
	void draw()
	{
		Vec3 drawpos = new Vec3(position);
		Vec3 shake_rot = new Vec3(0,0,0);
		if(damage_timer > 0){
			drawpos.x += Hell_randInt(-10,10) / 40.0 / DAMAGE_WAIT * damage_timer;
			drawpos.y += Hell_randInt(-10,10) / 40.0 / DAMAGE_WAIT * damage_timer;
			drawpos.z += Hell_randInt(-10,10) / 40.0 / DAMAGE_WAIT * damage_timer;
			shake_rot.x = Hell_randInt(-10,10) * 5.0 / DAMAGE_WAIT * damage_timer;
			shake_rot.y = Hell_randInt(-10,10) * 5.0 / DAMAGE_WAIT * damage_timer;
			shake_rot.z = Hell_randInt(-10,10) * 5.0 / DAMAGE_WAIT * damage_timer;
		}
		
		float sz = getSize();
		if(spec.type == EnemySpec.TYPE.TANK){
			float r = 0.2 , g = 0.6 , b = 0.2;
			if(life > 4){
				r = 1.0;
				g = 0.6;
				b = 0.2;
			}
			
			// 本体
			glPushMatrix();
			{
				glTranslatef(drawpos.x , drawpos.y ,drawpos.z);
				glRotatef(0 , 0 , rotation.z / 3.141592 * 180);
				glRotatef(shake_rot.y , shake_rot.z , shake_rot.x);
				
				glScalef(sz , sz , sz);
				glColor4f(r , g , b , 1);
				TankShape.drawPolygonBase();
				glColor4f(r/2 , g/2 , b/2 , 1);
				TankShape.drawWireBase();
			}
			glPopMatrix();
			
			// 放蕩
			glPushMatrix();
			{
				glTranslatef(drawpos.x , drawpos.y ,drawpos.z);
				glRotatef(0 , 0 , tarlet / 3.141592 * 180);
				glRotatef(shake_rot.y , shake_rot.z , shake_rot.x);
				glTranslatef(-tarlet_nockback , 0 , 0);
				
				if(tarlet_mode == TARLET.RELOAD){
					r = r*0.5;
					g = g*0.5;
					b = b*0.5;
				}else if(tarlet_mode == TARLET.FIRE){
					r = g = b = 2;
				}
				
				glScalef(sz , sz , sz);
				glColor4f(r , g , b , 1);
				TankShape.drawPolygonTarlet();
				glColor4f(r/2 , g/2 , b/2 , 1);
				TankShape.drawWireTarlet();
			}
			glPopMatrix();
		}
	}
	void drawHigh(){
		Hell_setAlpha(HELL_ALPHA_ADD);
		
		if(spec.type == EnemySpec.TYPE.TANK){
			if(tarlet_mode == TARLET.TARGET){
				glPushMatrix();
				{
					glTranslatef(position.x , position.y ,position.z);
					glRotatef(0 , 0 , tarlet / 3.141592 * 180);
					
					glColor4f(1.0 , 0.1 , 0.1 , 0.2);
					LineShape.drawWireThin(new Vec3(1,0,0) , new Vec3(MAX_RANGE,0,0));
				}
				glPopMatrix();
			}
			if(tarlet_mode == TARLET.FIRE){
				glPushMatrix();
				{
					glTranslatef(position.x , position.y ,position.z);
					glRotatef(0 , 0 , tarlet / 3.141592 * 180);
					
					glColor4f(1.0 , 0.1 , 0.1 , 0.3);
					LineShape.drawWire(new Vec3(1,0,0) , new Vec3(MAX_RANGE,0,0));
					glColor4f(1.0 , 0.1 , 0.1 , 0.1);
					LineShape.drawWire(new Vec3(1,0,0) , new Vec3(MAX_RANGE*2,0,0));
				}
				glPopMatrix();
			}
		}else if(spec.type == EnemySpec.TYPE.BULLET){
			// 弾
			glPushMatrix();
			{
				glTranslatef(position.x , position.y ,position.z);
				glRotatef(0 , 0 , rotation.z * 180 / 3.141592);
				glRotatef(rotation.x ,rotation.y ,0);
				
				float sz = getSize() * 2;
				if(timer < 15) sz *= (15 - timer)/3;
				glScalef(sz , sz , sz);
				glColor4f(0.9 , 0.7 , 0.1 , 0.7);
				NeedleShape.drawWire();
			}
			glPopMatrix();
		}
		Hell_setAlpha(HELL_ALPHA_NORMAL);
	}
	
	float getSize()
	{
		return spec.size;
	}
}